package ca.cbc.security;

import java.util.Map;
import java.security.Principal;
import javax.security.auth.login.LoginContext;
import javax.security.auth.Subject;
import javax.security.auth.callback.*;
import javax.security.auth.login.*;
import javax.security.auth.spi.LoginModule;
import java.io.IOException;
import java.sql.SQLException;

import java.util.*;
import org.apache.log4j.Logger;

public class CBCLoginModule implements LoginModule {

    private static Logger log = Logger.getLogger(CBCLoginModule.class);

    protected CallbackHandler callbackHandler = null;
    protected boolean committed = false;
    protected boolean debug = false;
    protected Map options = null;
    protected Principal principal = null;
    protected Map sharedState = null;
    protected Subject subject = null;

    public boolean abort() throws LoginException {
        return (true);
    }

    public boolean commit() throws LoginException {
        // If authentication was not successful, just return false
        if (principal == null){
            return (false);
        }
        if (!subject.getPrincipals().contains(principal))
            subject.getPrincipals().add(principal);

        // add role principals
		AuthDBData db = new AuthDBData();
		
		ArrayList<String> roles = null;

		try {
			roles = db.getUserRoles(principal.toString());
		} catch (SQLException e) {
			log.error("SQL Exception Thrown : " + e + " : " + e.getMessage());
		}

		for(String role : roles) {
			subject.getPrincipals().add(new CBCRolePrincipal(role));
		}

        committed = true;
        return (true);
 
    }

    public void initialize(Subject subject, CallbackHandler callbackHandler,
                           Map sharedState, Map options) {
 
        // Save configuration values
        this.subject = subject;
        this.callbackHandler = callbackHandler;
        this.sharedState = sharedState;
        this.options = options;
 
 
    }

   public boolean login() throws LoginException {
        // Set up our CallbackHandler requests
        if (callbackHandler == null)
            throw new LoginException("No CallbackHandler specified");
        Callback callbacks[] = new Callback[2];
        callbacks[0] = new NameCallback("Username: ");
        callbacks[1] = new PasswordCallback("Password: ", false);
 
        // Interact with the user to retrieve the username and password
        String username = null;
        String password = null;
        try {
            callbackHandler.handle(callbacks);
            username = ((NameCallback) callbacks[0]).getName();
            password =
                new String(((PasswordCallback) callbacks[1]).getPassword());
        } catch (IOException e) {
            throw new LoginException(e.toString());
        } catch (UnsupportedCallbackException e) {
            throw new LoginException(e.toString());
        }

        if (!authenticate(username,password)) 
            return false;

		principal  = new CBCPrincipal(username);
		return true;
 
    }
 
    public boolean logout() throws LoginException {
 
        subject.getPrincipals().remove(principal);
        committed = false;
        principal = null;
        return (true);
 
    }

    boolean authenticate(String s,String p){

		AuthDBData db = new AuthDBData();
		boolean authenticated = false;

		try {
			authenticated = db.authenticate(s,p);
		} catch (SQLException e) {
			log.error("SQLException Thrown : " + e + " : " + e.getMessage());
		}

		return authenticated;

    }
    
    static public void main(String args[]) throws Exception{
        LoginContext ctx = new LoginContext("TomcatAuthentication");
        ctx.login();
        
    } 
}

